/*
 * Copyright (C) 2016  Nicola Spanti (RyDroid) <dev@nicola-spanti.info>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */


#include "PlanetWars2dRT-core/specific/model/planet_observer.h"
#include "PlanetWars2dRT-core/specific/controller/planet_observer.h"
#include "PlanetWars2dRT-core/specific/model/planet_position.h"
#include "PlanetWars2dRT-core/specific/model/planet_size.h"
#include "PlanetWars2dRT-core/specific/model/ship_position.h"


EXTERN_C_BEGIN


void
planet_observer_new_ship_square_dispatcher_handler(void* an_observable,
						   void* observer_data
						   __attribute__((unused)),
						   void* event_data)
{
  if(an_observable != NULL && event_data != NULL)
    {
      const observer_data_with_code* data
	= (observer_data_with_code*) event_data;
      if(data->code == PLANET_OBSERVER_CODE_SHIP_CREATED)
	{
	  if(data->data != NULL)
	    {
	      const planet_t* a_planet = (const planet_t*) an_observable;
	      ship_t* a_ship = (ship_t*) data->data;
	      
	      unsigned int max_distance2 = planet_get_radius(a_planet) * 2 +1;
	      unsigned int x_to_go = planet_get_top_left_position_x(a_planet);
	      unsigned int y_to_go = planet_get_top_left_position_y(a_planet);
	      x_to_go += rand() % max_distance2;
	      y_to_go += rand() % max_distance2;
	      ship_set_top_left_position_to_go_x(a_ship, x_to_go);
	      ship_set_top_left_position_to_go_y(a_ship, y_to_go);
	    }
	}
    }
}

void
planet_observer_new_ship_circle_dispatcher_handler(void* an_observable,
						   void* observer_data,
						   void* event_data)
{
  if(an_observable != NULL && event_data != NULL)
    {
      const observer_data_with_code* data
	= (observer_data_with_code*) event_data;
      if(data->code == PLANET_OBSERVER_CODE_SHIP_CREATED)
	{
	  if(data->data != NULL)
	    {
	      const planet_t* a_planet = (const planet_t*) an_observable;
	      ship_t* a_ship = (ship_t*) data->data;
	      float factor_radius_max = * (float*) observer_data;
	      
	      unsigned int max_distance = planet_get_radius(a_planet) * factor_radius_max;
	      unsigned int distance     = rand() % max_distance;
	      unsigned short angle      = rand();
	      unsigned int x_to_go = planet_get_center_position_x(a_planet);
	      unsigned int y_to_go = planet_get_center_position_y(a_planet);
	      x_to_go += cos(angle) * distance;
	      y_to_go += sin(angle) * distance;
	      ship_set_top_left_position_to_go_x(a_ship, x_to_go);
	      ship_set_top_left_position_to_go_y(a_ship, y_to_go);
	    }
	}
    }
}

void
planet_observer_new_ship_circle_dispatcher_data_free(void* data)
{
  if(data != NULL)
    {
      free(data);
    }
}

struct observer_t
planet_observer_new_ship_square_dispatcher_create(void)
{
  struct observer_t an_observer;
  observer_init_first_time_only_unsafe(&an_observer);
  an_observer.handler = planet_observer_new_ship_square_dispatcher_handler;
  return an_observer;
}

struct observer_t
planet_observer_new_ship_circle_dispatcher_create(float factor_radius_max)
{
  struct observer_t an_observer;
  an_observer.handler = planet_observer_new_ship_circle_dispatcher_handler;
  an_observer.data = (float*) malloc(sizeof(float));
  *((float*) an_observer.data) = factor_radius_max;
  an_observer.data_free = planet_observer_new_ship_circle_dispatcher_data_free;
  return an_observer;
}

struct observer_t
planet_observer_new_ship_circle_dispatcher_create_default(void)
{
  return planet_observer_new_ship_circle_dispatcher_create(1.5);
}

struct observer_t
planet_observer_new_ship_default_dispatcher_create(void)
{
  return planet_observer_new_ship_circle_dispatcher_create_default();
}


EXTERN_C_END
